#include "MVDataSubMB.h"

#include "MVDataMB.h"
#include <list>

CMVDataSubMB::CMVDataSubMB( TYPE_SUB_MB type )
{
	m_typeSubMBType = type;
	m_eSubMBType = type;
	m_eLoc = LOC_BLOCK_MAX;
	m_plstSubSubMB = new std::list<CMVDataSubSubMB*>();
}

CMVDataSubMB::CMVDataSubMB( const CMVDataSubMB & sub_mb ) : CMVDataMBCommon( static_cast<const CMVDataMBCommon>( sub_mb ) )
{
	m_typeSubMBType = sub_mb.m_typeSubMBType;
	m_eSubMBType = sub_mb.m_typeSubMBType;
	m_eLoc = sub_mb.GetLoc();
	m_plstSubSubMB = new std::list<CMVDataSubSubMB*>();

	m_plstSubSubMB->assign( sub_mb.m_plstSubSubMB->begin(), sub_mb.m_plstSubSubMB->end() );
}

CMVDataSubMB::CMVDataSubMB()
{
	//TODO
	m_typeSubMBType = TYPE_SUB_MB_NO_USE;
	m_eSubMBType = TYPE_SUB_MB_NO_USE;
	m_eLoc = LOC_BLOCK_MAX;
	m_plstSubSubMB = new std::list<CMVDataSubSubMB*>();
}

CMVDataSubMB::~CMVDataSubMB()
{
	delete m_plstSubSubMB;
}

int CMVDataSubMB::SetSubMBType( TYPE_SUB_MB mbtype )
{
	m_typeSubMBType = mbtype;
	m_eSubMBType = mbtype;
	return 0;

}
TYPE_SUB_MB CMVDataSubMB::GetSubMBType() const
{
	return m_typeSubMBType;
}

int CMVDataSubMB::AddSubSubMB( const CMVDataSubSubMB * sub_sub_mb )
{
	CMVDataSubSubMB * sub_sub_mb_new = new CMVDataSubSubMB( *sub_sub_mb );
	m_plstSubSubMB->push_back( sub_sub_mb_new );

	return 0;
}

const CMVDataSubSubMB * CMVDataSubMB::GetSubSubMBByLocation( LOC_BLOCK mbloc ) const
{

	if( m_plstSubSubMB->empty() )
	{
		return NULL;
	}

	std::list<CMVDataSubSubMB*>::iterator i = m_plstSubSubMB->begin();
	for( ; i != m_plstSubSubMB->end(); i++ )
	{
		if( (*i)->GetLoc() == mbloc )
		{
			return (*i);
		}

	}
	return NULL;

}

const CMVDataSubSubMB * CMVDataSubMB::GetNextSubSubMB( const CMVDataSubSubMB * curr_sub_sub_mb ) const
{

	if ( m_plstSubSubMB->empty() )
	{
		return NULL;
	}

	if( NULL == curr_sub_sub_mb )
	{
		return *(m_plstSubSubMB->begin());
	}

	std::list<CMVDataSubSubMB*>::iterator i = m_plstSubSubMB->begin();
	for( ; i != m_plstSubSubMB->end(); i++ )
	{
		if( (*i) == curr_sub_sub_mb )
		{
			i++;
			if( i != m_plstSubSubMB->end() )
			{
				return (*i);
			}

			break;
		}

	}

	return NULL;

}

bool CMVDataSubMB::HaveSubSubMB() const
{
	if ( m_plstSubSubMB->size() != 0 )
	{
		return true;
	}

	return false;
}

bool CMVDataSubMB::ShouldHaveSubSubMB() const
{
	// TODO
	return true;
}


int CMVDataSubMB::SetLoc( LOC_BLOCK loc )
{
	m_eLoc = loc;

	return 0;
}

LOC_BLOCK CMVDataSubMB::GetLoc() const
{
	return m_eLoc;
}

CMVDataSubMB& CMVDataSubMB::operator = ( const CMVDataSubMB& sub_mb )
{

	static_cast<CMVDataMBCommon>( *this ) = static_cast<CMVDataMBCommon>( sub_mb );

	m_eLoc = sub_mb.m_eLoc;
	m_typeSubMBType = sub_mb.m_typeSubMBType;

	m_plstSubSubMB->clear();
	m_plstSubSubMB->assign( sub_mb.m_plstSubSubMB->begin(), sub_mb.m_plstSubSubMB->end() );

	return *this;
}

int CMVDataSubMB::CopyDataFromBlock( const CMVDataBlock * block )
{
	if ( block->GetShape() != SHAPE_BLOCK_SUB_MB )
	{
		return -1;
	}

	// TODO 优化拷贝
	if( block->HaveASAD() ) SetASAD( block->GetASAD() );
	if( block->HaveSADBitCount() ) SetSADBitCount( block->GetSADBitCount() );
	if( block->HaveMVCoordinate() ) SetMVCoordinate( block->GetMVCoordinateX(), block->GetMVCoordinateY() );

	m_eLoc = block->GetFirstLayerLoc();
	switch( m_eLoc )
	{
	case LOC_BLOCK_UP:
	case LOC_BLOCK_DOWN:
	case LOC_BLOCK_LEFT:
	case LOC_BLOCK_RIGHT:
		m_typeSubMBType = TYPE_SUB_MB_NO_USE;
		break;

	case LOC_BLOCK_DOWNLEFT:
	case LOC_BLOCK_DOWNRIGHT:
	case LOC_BLOCK_UPLEFT:
	case LOC_BLOCK_UPRIGHT:
		m_typeSubMBType = TYPE_SUB_MB_8x8;
		break;

	}

	m_eSubMBType = m_typeSubMBType;

	return 0;
}

bool CMVDataSubMB::CheckValidation() const
{
	const CMVDataSubSubMB * pSubSubMB = NULL;

	unsigned char block_bitmap = 0;

	while( pSubSubMB = GetNextSubSubMB( pSubSubMB ) )
	{
		if( block_bitmap & LOC_BLOCK_BITMAP_IN_2X2[pSubSubMB->GetLoc()] == 0 )
		{
			block_bitmap |= LOC_BLOCK_BITMAP_IN_2X2[pSubSubMB->GetLoc()];
		}
		else
		{
			return false;
		}

	}

	if( block_bitmap == 0xFF )
	{
		return true;
	}
	else
	{
		return false;
	}
	return true;
}